home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / dviware / dvibook / Dviselect / dviselect.c < prev    next >
C/C++ Source or Header  |  1994-03-18  |  24KB  |  1,055 lines

  1. /*
  2.  * Copyright (c) 1987, 1989 University of Maryland
  3.  * Department of Computer Science.  All rights reserved.
  4.  * Permission to copy for any purpose is hereby granted
  5.  * so long as this copyright notice remains intact.
  6.  */
  7.  
  8. #ifndef lint
  9. static char rcsid[] = "$Header: /usr/src/local/tex/local/mctex/dvi/RCS/dviselect.c,v 3.1 89/08/22 17:16:13 chris Exp $";
  10. #endif
  11.  
  12. /*
  13.  * DVI page selection program
  14.  *
  15.  * Reads DVI version 2 files and selects pages, writing a new DVI
  16.  * file.  The new DVI file is technically correct, though we do not
  17.  * adjust the tallest and widest page values, nor the DVI stack size.
  18.  * This is all right since the values will never become too small,
  19.  * but it might be nice to fix them up.  Perhaps someday . . . .
  20.  */
  21.  
  22. #include "libtex/types.h"
  23. #include "libtex/dviclass.h"
  24. #include "libtex/dvicodes.h"
  25. #include "libtex/error.h"
  26. #include "libtex/fio.h"
  27. #include "libtex/gripes.h"
  28. #include "libtex/search.h"
  29. #include <stdio.h>
  30. #include <ctype.h>
  31.  
  32. #define white(x) ((x) == ' ' || (x) == '\t' || (x) == ',')
  33.  
  34. char  *ProgName;
  35. extern char *optarg;
  36. extern int   optind;
  37.  
  38. /* Globals */
  39. char    serrbuf[BUFSIZ];    /* buffer for stderr */
  40.  
  41. /*
  42.  * We will try to keep output lines shorter than MAXCOL characters.
  43.  */
  44. #define MAXCOL    75
  45.  
  46. /*
  47.  * We use the following structure to keep track of fonts we have seen.
  48.  * The final DVI file lists only the fonts it uses.
  49.  */
  50. struct fontinfo {
  51.     i32    fi_newindex;    /* font number in output file */
  52.     int    fi_reallyused;    /* true => used on a page we copied */
  53.     i32    fi_checksum;    /* the checksum */
  54.     i32    fi_mag;        /* the magnification */
  55.     i32    fi_designsize;    /* the design size */
  56.     short    fi_n1;        /* the name header length */
  57.     short    fi_n2;        /* the name body length */
  58.     char    *fi_name;    /* the name itself */
  59. };
  60.  
  61. /*
  62.  * We need to remember which pages the user would like.  We build a linked
  63.  * list that allows us to decide (for any given page) whether it should
  64.  * be included in the output file.  Each page has ten \count variables
  65.  * associated with it.  We put a bound on the values allowed for each, and
  66.  * keep a linked list of alternatives should any be outside the allowed
  67.  * range.  For example, `dviselect *.3,10-15' would generate a two-element
  68.  * page list, with the first allowing any value for \count0 (and \counts 2 to
  69.  * 9) but \count1 restricted to the range 3-3, and the second restricting
  70.  * \count0 to the range 10-15 but leaving \counts 1 to 9 unrestrained.
  71.  *
  72.  * We remember whether a bound is specified, so that we need not fix
  73.  * some `large' number as a maximum value.
  74.  *
  75.  * We also allow `absolute' page references, where the first page is
  76.  * page 1, the second 2, and so forth.  These are specified with an
  77.  * equal sign: `dviselect =4:10' picks up the fourth through tenth
  78.  * sequential pages, irrespective of \count values.
  79.  *
  80.  * There is also an even/odd switch (which can be applied to absolute
  81.  * or relative pages): dviselect =even, even.3, etc.
  82.  */
  83. enum pstype {
  84.     pt_lu,            /* have both lower and upper bounds */
  85.     pt_l,            /* lower bound only */
  86.     pt_u,            /* upper bound only */
  87.     pt_unbounded,        /* any value at all */
  88.     pt_even,        /* even values only */
  89.     pt_odd            /* odd values only */
  90. };
  91. struct pagesel {
  92.     enum pstype ps_type;    /* type of selector */
  93.     i32    ps_low;        /* lower bound */
  94.     i32    ps_high;    /* upper bound */
  95. };
  96. struct pagelist {
  97.     struct    pagelist *pl_alt;    /* next in a series of alternates */
  98.     int    pl_len;            /* number of ranges to check */
  99.     int    pl_abs;            /* true iff absolute page ref */
  100.     struct    pagesel pl_pages[10];    /* one for each \count variable */
  101. };
  102.  
  103. int    SFlag;            /* true => -s, silent operation */
  104.  
  105. struct    search *FontFinder;    /* maps from input indicies to fontinfo */
  106. i32    NextOutputFontIndex;    /* generates output indicies */
  107. i32    CurrentFontIndex;    /* current (old) index in input */
  108. i32    OutputFontIndex;    /* current (new) index in ouput */
  109.  
  110. struct    pagelist *PageList;    /* the list of allowed pages */
  111.  
  112. char    *DVIFileName;        /* name of input DVI file */
  113. FILE    *inf;            /* the input file itself */
  114. FILE    *outf;            /* the output DVI file */
  115.  
  116. long    StartOfLastPage;    /* The file position just before we started
  117.                    the last page (this is later written to
  118.                    the output file as the previous page
  119.                    pointer). */
  120. long    CurrentPosition;    /* The current position of the file */
  121.  
  122. int    UseThisPage;        /* true => current page is selected */
  123.  
  124. i32    InputPageNumber;    /* current absolute page in old DVI file */
  125. int    NumberOfOutputPages;    /* number of pages in new DVI file */
  126.  
  127. i32    Numerator;        /* numerator from DVI file */
  128. i32    Denominator;        /* denominator from DVI file */
  129. i32    DVIMag;            /* magnification from DVI file */
  130.  
  131. i32    Count[10];        /* the 10 \count variables */
  132.  
  133. /* save some string space: we use this a lot */
  134. char    writeerr[] = "error writing DVI file";
  135.  
  136. char    *malloc(), *realloc();
  137. /*
  138.  * You may get lint warnings about sprintf's return value.
  139.  * Older versions of 4BSD have `char *sprintf()'.  ANSI and
  140.  * SysV use `int sprintf()'; so ignore the warnings.
  141.  */
  142.  
  143. /*
  144.  * Lint gets somewhat confused over putc.
  145.  */
  146. #ifdef lint
  147. #undef putc
  148. #ifdef ultrix /* grr */
  149. #define putc(c, f) fputc((char)(c), f)
  150. #else
  151. #define putc(c, f) fputc((int)(c), f)
  152. #endif
  153. #endif
  154.  
  155. /*
  156.  * Return true iff the 10 \counts are one of the desired output pages.
  157.  */
  158. DesiredPageP()
  159. {
  160.     register struct pagelist *pl;
  161.  
  162.     for (pl = PageList; pl != NULL; pl = pl->pl_alt) {
  163.         register struct pagesel *ps = pl->pl_pages;
  164.         register int i;
  165.         register i32 *pagep;
  166.  
  167.         pagep = pl->pl_abs ? &InputPageNumber : &Count[0];
  168.         for (i = 0; i < pl->pl_len; i++, ps++, pagep++) {
  169.             switch (ps->ps_type) {
  170.  
  171.             case pt_lu:    /* check upper, fall through */
  172.                 if (*pagep > ps->ps_high)
  173.                     goto no_good;
  174.                 /* FALLTHROUGH */
  175.  
  176.             case pt_l:    /* only if not too low */
  177.                 if (*pagep < ps->ps_low)
  178.                     goto no_good;
  179.                 break;
  180.  
  181.             case pt_u:    /* only if not too high */
  182.                 if (*pagep > ps->ps_high)
  183.                     goto no_good;
  184.                 break;
  185.  
  186.             case pt_unbounded:
  187.                 break;
  188.  
  189.             case pt_even:    /* only if even */
  190.                 if (*pagep & 1)
  191.                     goto no_good;
  192.                 break;
  193.  
  194.             case pt_odd:    /* only if odd */
  195.                 if ((*pagep & 1) == 0)
  196.                     goto no_good;
  197.                 break;
  198.             }
  199.         }
  200.         return (1);    /* success */
  201.     no_good:
  202.         continue;
  203.     }
  204.     return (0);
  205. }
  206.  
  207. /*
  208.  * Print a message to stderr, with an optional leading space, and handling
  209.  * long line wraps.
  210.  */
  211. message(space, str, len)
  212.     int space;
  213.     register char *str;
  214.     register int len;
  215. {
  216.     static int beenhere;
  217.     static int col;
  218.  
  219.     if (!beenhere)
  220.         space = 0, beenhere++;
  221.     if (len == 0)
  222.         len = strlen(str);
  223.     col += len;
  224.     if (space) {
  225.         if (col >= MAXCOL)
  226.             (void) putc('\n', stderr), col = len;
  227.         else
  228.             (void) putc(' ', stderr), col++;
  229.     }
  230.     while (--len >= 0)
  231.         (void) putc(*str++, stderr);
  232.     (void) fflush(stderr);
  233. }
  234.  
  235. /*
  236.  * Start a page (process a DVI_BOP).
  237.  */
  238. BeginPage()
  239. {
  240.     register i32 *i;
  241.  
  242.     OutputFontIndex = -1;    /* new page requires respecifying font */
  243.     InputPageNumber++;    /* count it */
  244.     for (i = Count; i < &Count[10]; i++)
  245.         fGetLong(inf, *i);
  246.     (void) GetLong(inf);    /* previous page pointer */
  247.  
  248.     if ((UseThisPage = DesiredPageP()) == 0)
  249.         return;
  250.  
  251.     putbyte(outf, DVI_BOP);
  252.     for (i = Count; i < &Count[10]; i++)
  253.         PutLong(outf, *i);
  254.     PutLong(outf, StartOfLastPage);
  255.     if (ferror(outf))
  256.         error(1, -1, writeerr);
  257.  
  258.     StartOfLastPage = CurrentPosition;
  259.     CurrentPosition += 45;    /* we just wrote this much */
  260.  
  261.     if (!SFlag) {        /* write nice page usage messages */
  262.         register int z = 0;
  263.         register int mlen = 0;
  264.         char msg[80];
  265.  
  266.         (void) sprintf(msg, "[%ld", (long)Count[0]);
  267.         mlen = strlen(msg);
  268.         for (i = &Count[1]; i < &Count[10]; i++) {
  269.             if (*i == 0) {
  270.                 z++;
  271.                 continue;
  272.             }
  273.             while (--z >= 0)
  274.                 msg[mlen++] = '.', msg[mlen++] = '0';
  275.             z = 0;
  276.             (void) sprintf(msg + mlen, ".%ld", (long)*i);
  277.             mlen += strlen(msg + mlen);
  278.         }
  279.         message(1, msg, mlen);
  280.     }
  281. }
  282.  
  283. /*
  284.  * End a page (process a DVI_EOP).
  285.  */
  286. EndPage()
  287. {
  288.  
  289.     if (!UseThisPage)
  290.         return;
  291.     if (!SFlag)
  292.         message(0, "]", 1);
  293.     putbyte(outf, DVI_EOP);
  294.     if (ferror(outf))
  295.         error(1, -1, writeerr);
  296.     CurrentPosition++;
  297.     NumberOfOutputPages++;
  298. }
  299.  
  300. /*
  301.  * For each of the fonts used in the new DVI file, write out a definition.
  302.  */
  303. /* ARGSUSED */
  304. void
  305. PostAmbleFontEnumerator(addr, key)
  306.     char *addr;
  307.     i32 key;
  308. {
  309.  
  310.     if (((struct fontinfo *)addr)->fi_reallyused)
  311.         WriteFont((struct fontinfo *)addr);
  312. }
  313.  
  314. HandlePostAmble()
  315. {
  316.     register i32 c;
  317.  
  318.     (void) GetLong(inf);    /* previous page pointer */
  319.     if (GetLong(inf) != Numerator)
  320.         GripeMismatchedValue("numerator");
  321.     if (GetLong(inf) != Denominator)
  322.         GripeMismatchedValue("denominator");
  323.     if (GetLong(inf) != DVIMag)
  324.         GripeMismatchedValue("\\magnification");
  325.  
  326.     putbyte(outf, DVI_POST);
  327.     PutLong(outf, StartOfLastPage);
  328.     PutLong(outf, Numerator);
  329.     PutLong(outf, Denominator);
  330.     PutLong(outf, DVIMag);
  331.     c = GetLong(inf);
  332.     PutLong(outf, c);    /* tallest page height */
  333.     c = GetLong(inf);
  334.     PutLong(outf, c);    /* widest page width */
  335.     c = GetWord(inf);
  336.     PutWord(outf, c);    /* DVI stack size */
  337.     PutWord(outf, NumberOfOutputPages);
  338.     StartOfLastPage = CurrentPosition;    /* point at post */
  339.     CurrentPosition += 29;    /* count all those `put's */
  340. #ifdef notdef
  341.     (void) GetWord(inf);    /* skip original number of pages */
  342. #endif
  343.  
  344.     /*
  345.      * just ignore all the incoming font definitions; we are done with
  346.      * input file 
  347.      */
  348.  
  349.     /*
  350.      * run through the FontFinder table and dump definitions for the
  351.      * fonts we have used. 
  352.      */
  353.     SEnumerate(FontFinder, PostAmbleFontEnumerator);
  354.  
  355.     putbyte(outf, DVI_POSTPOST);
  356.     PutLong(outf, StartOfLastPage);    /* actually start of postamble */
  357.     putbyte(outf, DVI_VERSION);
  358.     putbyte(outf, DVI_FILLER);
  359.     putbyte(outf, DVI_FILLER);
  360.     putbyte(outf, DVI_FILLER);
  361.     putbyte(outf, DVI_FILLER);
  362.     CurrentPosition += 10;
  363.     while (CurrentPosition & 3) {
  364.         putbyte(outf, DVI_FILLER);
  365.         CurrentPosition++;
  366.     }
  367.     if (ferror(outf))
  368.         error(1, -1, writeerr);
  369. }
  370.  
  371. /*
  372.  * Write a font definition to the output file
  373.  */
  374. WriteFont(fi)
  375.     register struct fontinfo *fi;
  376. {
  377.     register int l;
  378.     register char *s;
  379.  
  380.     if (fi->fi_newindex < 256) {
  381.         putbyte(outf, DVI_FNTDEF1);
  382.         putbyte(outf, fi->fi_newindex);
  383.         CurrentPosition += 2;
  384.     } else if (fi->fi_newindex < 65536) {
  385.         putbyte(outf, DVI_FNTDEF2);
  386.         PutWord(outf, fi->fi_newindex);
  387.         CurrentPosition += 3;
  388.     } else if (fi->fi_newindex < 16777216) {
  389.         putbyte(outf, DVI_FNTDEF3);
  390.         Put3Byte(outf, fi->fi_newindex);
  391.         CurrentPosition += 4;
  392.     } else {
  393.         putbyte(outf, DVI_FNTDEF4);
  394.         PutLong(outf, fi->fi_newindex);
  395.         CurrentPosition += 5;
  396.     }
  397.     PutLong(outf, fi->fi_checksum);
  398.     PutLong(outf, fi->fi_mag);
  399.     PutLong(outf, fi->fi_designsize);
  400.     putbyte(outf, fi->fi_n1);
  401.     putbyte(outf, fi->fi_n2);
  402.     l = fi->fi_n1 + fi->fi_n2;
  403.     CurrentPosition += 14 + l;
  404.     s = fi->fi_name;
  405.     while (--l >= 0)
  406.         putbyte(outf, *s++);
  407. }
  408.  
  409. /*
  410.  * Handle the preamble.  Someday we should update the comment field.
  411.  */
  412. HandlePreAmble()
  413. {
  414.     register int n, c;
  415.  
  416.     c = getc(inf);
  417.     if (c == EOF)
  418.         GripeUnexpectedDVIEOF();
  419.     if (c != DVI_PRE)
  420.         GripeMissingOp("PRE");
  421.     if (getc(inf) != DVI_VERSION)
  422.         error(1, 0, "%s is not a DVI version %d file",
  423.             DVIFileName, DVI_VERSION);
  424.     Numerator = GetLong(inf);
  425.     Denominator = GetLong(inf);
  426.     DVIMag = GetLong(inf);
  427.     putbyte(outf, DVI_PRE);
  428.     putbyte(outf, DVI_VERSION);
  429.     PutLong(outf, Numerator);
  430.     PutLong(outf, Denominator);
  431.     PutLong(outf, DVIMag);
  432.  
  433.     n = UnSign8(GetByte(inf));
  434.     CurrentPosition = 15 + n;    /* well, almost */
  435.     putbyte(outf, n);
  436.     while (--n >= 0) {
  437.         c = GetByte(inf);
  438.         putbyte(outf, c);
  439.     }
  440. }
  441.  
  442. main(argc, argv)
  443.     int argc;
  444.     register char **argv;
  445. {
  446.     register int c;
  447.     register char *s;
  448.     char *outname = NULL;
  449.  
  450.     ProgName = *argv;
  451.     setbuf(stderr, serrbuf);
  452.  
  453.     while ((c = getopt(argc, argv, "i:o:s")) != EOF) {
  454.         switch (c) {
  455.  
  456.         case 's':    /* silent */
  457.             SFlag++;
  458.             break;
  459.  
  460.         case 'i':
  461.             if (DVIFileName != NULL)
  462.                 goto usage;
  463.             DVIFileName = optarg;
  464.             break;
  465.  
  466.         case 'o':
  467.             if (outname != NULL)
  468.                 goto usage;
  469.             outname = optarg;
  470.             break;
  471.  
  472.         case '?':
  473. usage:
  474.             (void) fprintf(stderr, "\
  475. Usage: %s [-s] [-i infile] [-o outfile] pages [...] [infile [outfile]]\n",
  476.                 ProgName);
  477.             (void) fflush(stderr);
  478.             exit(1);
  479.         }
  480.     }
  481.  
  482.     while (optind < argc) {
  483.         s = argv[optind++];
  484.         c = *s;
  485.         if (!isalpha(c) && c != '/' ||
  486.             (c == 'e' || c == 'o') && evenodd(s)) {
  487.             if (ParsePages(s))
  488.                 goto usage;
  489.         } else if (DVIFileName == NULL)
  490.             DVIFileName = s;
  491.         else if (outname == NULL)
  492.             outname = s;
  493.         else
  494.             goto usage;
  495.     }
  496.     if (PageList == NULL)
  497.         goto usage;
  498.     if (DVIFileName == NULL) {
  499.         DVIFileName = "`stdin'";
  500.         inf = stdin;
  501.     } else if ((inf = fopen(DVIFileName, "r")) == 0)
  502.         error(1, -1, "cannot read %s", DVIFileName);
  503.     if (outname == NULL)
  504.         outf = stdout;
  505.     else if ((outf = fopen(outname, "w")) == 0)
  506.         error(1, -1, "cannot write %s", outname);
  507.  
  508.     if ((FontFinder = SCreate(sizeof(struct fontinfo))) == 0)
  509.         error(1, 0, "cannot create font finder (out of memory?)");
  510.  
  511.     StartOfLastPage = -1;
  512.     HandlePreAmble();
  513.     HandleDVIFile();
  514.     HandlePostAmble();
  515.     if (!SFlag)
  516.         (void) fprintf(stderr, "\nWrote %d page%s, %ld bytes\n",
  517.             NumberOfOutputPages, NumberOfOutputPages == 1 ? "" : "s",
  518.             (long)CurrentPosition);
  519.     exit(0);
  520.     /* NOTREACHED */
  521. }
  522.  
  523. struct pagelist *
  524. InstallPL(ps, n, absolute)
  525.     register struct pagesel *ps;
  526.     register int n;
  527.     int absolute;
  528. {
  529.     register struct pagelist *pl;
  530.  
  531.     pl = (struct pagelist *)malloc(sizeof *pl);
  532.     if (pl == NULL)
  533.         GripeOutOfMemory(sizeof *pl, "page list");
  534.     pl->pl_alt = PageList;
  535.     PageList = pl;
  536.     pl->pl_len = n;
  537.     while (--n >= 0)
  538.         pl->pl_pages[n] = ps[n];
  539.     pl->pl_abs = absolute;
  540. }
  541.  
  542. /*
  543.  * Return true iff the string `s' is the word `even' or `odd',
  544.  * followed by `.' or `white' characters.
  545.  */
  546. int
  547. evenodd(s)
  548.     char *s;
  549. {
  550.     register int c;
  551.  
  552.     if (strncmp(s, "even", 4) == 0)
  553.         c = s[4];
  554.     else if (strncmp(s, "odd", 3) == 0)
  555.         c = s[3];
  556.     else
  557.         return (0);
  558.     if (c == 0 || c == '.' || white(c))
  559.         return (1);
  560.     return (0);
  561. }
  562.  
  563. /*
  564.  * Parse a string representing a list of pages.  Return 0 iff ok.  As a
  565.  * side effect, the page selection(s) is (are) prepended to PageList.
  566.  */
  567. ParsePages(s)
  568.     register char *s;
  569. {
  570.     register struct pagesel *ps;
  571.     register int c;        /* current character */
  572.     register i32 n;        /* current numeric value */
  573.     register int innumber;    /* true => gathering a number */
  574.     int i;            /* next index in page select list */
  575.     int range;        /* true => saw a range indicator */
  576.     int negative;        /* true => number being built is negative */
  577.     int absolute;        /* true => absolute, not \count */
  578.     int lb, ub, even, odd;    /* flags for lower,upper,even,odd */
  579.     struct pagesel pagesel[10];
  580.  
  581.     range = 0;
  582.     innumber = 0;
  583.     absolute = 0;
  584.     i = 0;
  585.     ps = pagesel;
  586.     lb = ub = even = odd = 0;
  587.     /*
  588.      * Talk about ad hoc!  (Not to mention convoluted.)
  589.      */
  590.     for (;;) {
  591.         c = *s++;
  592.         if (i == 0 && !innumber && !range) {
  593.             /* nothing special going on */
  594.             if (c == 0)
  595.                 return 0;
  596.             if (white(c))
  597.                 continue;
  598.         }
  599.         if ((c == 'e' || c == 'o') && evenodd(s - 1)) {
  600.             if (innumber || range)
  601.                 return (-1);
  602.             if (c == 'e') {
  603.                 s += 3;
  604.                 even = 1;
  605.             } else {
  606.                 s += 2;
  607.                 odd = 1;
  608.             }
  609.             c = *s++;
  610.             goto finishnum;
  611.         }
  612.         if (c == '_') {
  613.             /* kludge: should be '-' for negatives */
  614.             if (innumber || absolute)
  615.                 return (-1);
  616.             innumber = 1;
  617.             negative = 1;
  618.             n = 0;
  619.             continue;
  620.         }
  621.         if (c == '=') {
  622.             /* absolute page */
  623.             if (innumber || range || i > 0)
  624.                 return (-1);
  625.             absolute = 1;
  626.             negative = 0;
  627.             n = 0;
  628.             continue;
  629.         }
  630.         if (isdigit(c)) {
  631.             /* accumulate numeric value */
  632.             if (!innumber) {
  633.                 innumber = 1;
  634.                 negative = 0;
  635.                 n = c - '0';
  636.                 continue;
  637.             }
  638.             n *= 10;
  639.             n += negative ? '0' - c : c - '0';
  640.             continue;
  641.         }
  642.         if (c == '-' || c == ':') {
  643.             /* here is a range */
  644.             if (range)
  645.                 return (-1);
  646.             if (innumber) {    /* have a lower bound */
  647.                 ps->ps_low = n;
  648.                 lb = 1;
  649.             }
  650.             range = 1;
  651.             innumber = 0;
  652.             continue;
  653.         }
  654.         if (c == '*') {
  655.             /* no lower bound, no upper bound */
  656.             c = *s++;
  657.             if (innumber || range || (c && c != '.' && !white(c)))
  658.                 return (-1);
  659.             goto finishnum;
  660.         }
  661.         if (c == 0 || c == '.' || white(c)) {
  662.             /* end of this range */
  663.             if (innumber) {        /* have an upper bound */
  664.                 ps->ps_high = n;
  665.                 ub = 1;
  666.                 if (!range) {
  667.                     /* no range => lower bound == upper */
  668.                     ps->ps_low = ps->ps_high;
  669.                     lb = 1;
  670.                 }
  671.             }
  672. finishnum:
  673.             if (even)
  674.                 ps->ps_type = pt_even;
  675.             else if (odd)
  676.                 ps->ps_type = pt_odd;
  677.             else if (lb)
  678.                 ps->ps_type = ub ? pt_lu : pt_l;
  679.             else
  680.                 ps->ps_type = ub ? pt_u : pt_unbounded;
  681.             if (c == '.') {
  682.                 if (absolute)
  683.                     return (-1);
  684.                 if (++i >= 10)    /* too many specifiers */
  685.                     return (-1);
  686.                 ps++;
  687.             } else {
  688.                 InstallPL(pagesel, i + 1, absolute);
  689.                 ps = pagesel;
  690.                 i = 0;
  691.                 absolute = 0;
  692.             }
  693.             if (c == 0)
  694.                 return (0);
  695.             range = 0;
  696.             innumber = 0;
  697.             lb = ub = even = odd = 0;
  698.             continue;
  699.         }
  700.         /* illegal character */
  701.         return (-1);
  702.     }
  703. }
  704.  
  705. /*
  706.  * Handle a font definition.
  707.  */
  708. HandleFontDef(index)
  709.     i32 index;
  710. {
  711.     register struct fontinfo *fi;
  712.     register int i;
  713.     register char *s;
  714.     int def = S_CREATE | S_EXCL;
  715.  
  716.     if ((fi = (struct fontinfo *)SSearch(FontFinder, index, &def)) == 0)
  717.         if (def & S_COLL)
  718.             error(1, 0, "font %ld already defined", (long)index);
  719.         else
  720.             error(1, 0, "cannot stash font %ld (out of memory?)",
  721.                 (long)index);
  722.     fi->fi_reallyused = 0;
  723.     fi->fi_checksum = GetLong(inf);
  724.     fi->fi_mag = GetLong(inf);
  725.     fi->fi_designsize = GetLong(inf);
  726.     fi->fi_n1 = UnSign8(GetByte(inf));
  727.     fi->fi_n2 = UnSign8(GetByte(inf));
  728.     i = fi->fi_n1 + fi->fi_n2;
  729.     if ((s = malloc((unsigned)i)) == 0)
  730.         GripeOutOfMemory(i, "font name");
  731.     fi->fi_name = s;
  732.     while (--i >= 0)
  733.         *s++ = GetByte(inf);
  734. }
  735.  
  736. /*
  737.  * Handle a \special.
  738.  */
  739. HandleSpecial(c, l, p)
  740.     int c;
  741.     register int l;
  742.     register i32 p;
  743. {
  744.     register int i;
  745.  
  746.     if (UseThisPage) {
  747.         putbyte(outf, c);
  748.         switch (l) {
  749.  
  750.         case DPL_UNS1:
  751.             putbyte(outf, p);
  752.             CurrentPosition += 2;
  753.             break;
  754.  
  755.         case DPL_UNS2:
  756.             PutWord(outf, p);
  757.             CurrentPosition += 3;
  758.             break;
  759.  
  760.         case DPL_UNS3:
  761.             Put3Byte(outf, p);
  762.             CurrentPosition += 4;
  763.             break;
  764.  
  765.         case DPL_SGN4:
  766.             PutLong(outf, p);
  767.             CurrentPosition += 5;
  768.             break;
  769.  
  770.         default:
  771.             panic("HandleSpecial l=%d", l);
  772.             /* NOTREACHED */
  773.         }
  774.         CurrentPosition += p;
  775.         while (--p >= 0) {
  776.             i = getc(inf);
  777.             putbyte(outf, i);
  778.         }
  779.         if (feof(inf))
  780.             GripeUnexpectedDVIEOF();
  781.         if (ferror(outf))
  782.             error(1, -1, writeerr);
  783.     } else
  784.         while (--p >= 0)
  785.             (void) getc(inf);
  786. }
  787.  
  788. ReallyUseFont()
  789. {
  790.     register struct fontinfo *fi;
  791.     int look = S_LOOKUP;
  792.  
  793.     fi = (struct fontinfo *)SSearch(FontFinder, CurrentFontIndex, &look);
  794.     if (fi == NULL)
  795.         error(1, 0, "DVI file requested font %ld without defining it",
  796.             (long)CurrentFontIndex);
  797.     if (fi->fi_reallyused == 0) {
  798.         fi->fi_reallyused++;
  799.         fi->fi_newindex = NextOutputFontIndex++;
  800.         WriteFont(fi);
  801.     }
  802.     if (fi->fi_newindex != OutputFontIndex) {
  803.         PutFontSelector(fi->fi_newindex);
  804.         OutputFontIndex = fi->fi_newindex;
  805.     }
  806. }
  807.  
  808. /*
  809.  * Write a font selection command to the output file
  810.  */
  811. PutFontSelector(index)
  812.     i32 index;
  813. {
  814.  
  815.     if (index < 64) {
  816.         putbyte(outf, index + DVI_FNTNUM0);
  817.         CurrentPosition++;
  818.     } else if (index < 256) {
  819.         putbyte(outf, DVI_FNT1);
  820.         putbyte(outf, index);
  821.         CurrentPosition += 2;
  822.     } else if (index < 65536) {
  823.         putbyte(outf, DVI_FNT2);
  824.         PutWord(outf, index);
  825.         CurrentPosition += 3;
  826.     } else if (index < 16777216) {
  827.         putbyte(outf, DVI_FNT3);
  828.         Put3Byte(outf, index);
  829.         CurrentPosition += 4;
  830.     } else {
  831.         putbyte(outf, DVI_FNT4);
  832.         PutLong(outf, index);
  833.         CurrentPosition += 5;
  834.     }
  835. }
  836.  
  837. /*
  838.  * The following table describes the length (in bytes) of each of the DVI
  839.  * commands that we can simply copy, starting with DVI_SET1 (128).
  840.  */
  841. char    oplen[128] = {
  842.     0, 0, 0, 0,        /* DVI_SET1 .. DVI_SET4 */
  843.     9,            /* DVI_SETRULE */
  844.     0, 0, 0, 0,        /* DVI_PUT1 .. DVI_PUT4 */
  845.     9,            /* DVI_PUTRULE */
  846.     1,            /* DVI_NOP */
  847.     0,            /* DVI_BOP */
  848.     0,            /* DVI_EOP */
  849.     1,            /* DVI_PUSH */
  850.     1,            /* DVI_POP */
  851.     2, 3, 4, 5,        /* DVI_RIGHT1 .. DVI_RIGHT4 */
  852.     1,            /* DVI_W0 */
  853.     2, 3, 4, 5,        /* DVI_W1 .. DVI_W4 */
  854.     1,            /* DVI_X0 */
  855.     2, 3, 4, 5,        /* DVI_X1 .. DVI_X4 */
  856.     2, 3, 4, 5,        /* DVI_DOWN1 .. DVI_DOWN4 */
  857.     1,            /* DVI_Y0 */
  858.     2, 3, 4, 5,        /* DVI_Y1 .. DVI_Y4 */
  859.     1,            /* DVI_Z0 */
  860.     2, 3, 4, 5,        /* DVI_Z1 .. DVI_Z4 */
  861.     0,            /* DVI_FNTNUM0 (171) */
  862.     0, 0, 0, 0, 0, 0, 0, 0,    /* 172 .. 179 */
  863.     0, 0, 0, 0, 0, 0, 0, 0,    /* 180 .. 187 */
  864.     0, 0, 0, 0, 0, 0, 0, 0,    /* 188 .. 195 */
  865.     0, 0, 0, 0, 0, 0, 0, 0,    /* 196 .. 203 */
  866.     0, 0, 0, 0, 0, 0, 0, 0,    /* 204 .. 211 */
  867.     0, 0, 0, 0, 0, 0, 0, 0,    /* 212 .. 219 */
  868.     0, 0, 0, 0, 0, 0, 0, 0,    /* 220 .. 227 */
  869.     0, 0, 0, 0, 0, 0, 0,    /* 228 .. 234 */
  870.     0, 0, 0, 0,        /* DVI_FNT1 .. DVI_FNT4 */
  871.     0, 0, 0, 0,        /* DVI_XXX1 .. DVI_XXX4 */
  872.     0, 0, 0, 0,        /* DVI_FNTDEF1 .. DVI_FNTDEF4 */
  873.     0,            /* DVI_PRE */
  874.     0,            /* DVI_POST */
  875.     0,            /* DVI_POSTPOST */
  876.     0, 0, 0, 0, 0, 0,    /* 250 .. 255 */
  877. };
  878.  
  879. /*
  880.  * Here we read the input DVI file and write relevant pages to the
  881.  * output DVI file. We also keep track of font changes, handle font
  882.  * definitions, and perform some other housekeeping.
  883.  */
  884. HandleDVIFile()
  885. {
  886.     register int c, l;
  887.     register i32 p;
  888.     register int CurrentFontOK = 0;
  889.     int doingpage = 0;
  890.  
  891.     /* Only way out is via "return" statement */
  892.     for (;;) {
  893.         c = getc(inf);    /* getc() returns unsigned values */
  894.         if (DVI_IsChar(c)) {
  895.             /*
  896.              * Copy chars, note font usage, but ignore if
  897.              * page is not interesting.
  898.              */
  899.             if (!UseThisPage)
  900.                 continue;
  901.             if (!CurrentFontOK) {
  902.                 ReallyUseFont();
  903.                 CurrentFontOK++;
  904.             }
  905.             putbyte(outf, c);
  906.             CurrentPosition++;
  907.             continue;
  908.         }
  909.         if (DVI_IsFont(c)) {    /* note font change */
  910.             CurrentFontIndex = c - DVI_FNTNUM0;
  911.             CurrentFontOK = 0;
  912.             continue;
  913.         }
  914.         if (c == EOF)
  915.             GripeUnexpectedDVIEOF();
  916.         if ((l = (oplen - 128)[c]) != 0) {    /* simple copy */
  917.             if (!UseThisPage) {
  918.                 while (--l > 0)
  919.                     (void) getc(inf);
  920.                 continue;
  921.             }
  922.             CurrentPosition += l;
  923.             putbyte(outf, c);
  924.             while (--l > 0) {
  925.                 c = getc(inf);
  926.                 putbyte(outf, c);
  927.             }
  928.             if (ferror(outf))
  929.                 error(1, -1, writeerr);
  930.             continue;
  931.         }
  932.         if ((l = DVI_OpLen(c)) != 0) {
  933.             /*
  934.              * Handle other generics.
  935.              * N.B.: there should only be unsigned parameters
  936.              * here (save SGN4), for commands with negative
  937.              * parameters have been taken care of above.
  938.              */
  939.             switch (l) {
  940.  
  941.             case DPL_UNS1:
  942.                 p = getc(inf);
  943.                 break;
  944.  
  945.             case DPL_UNS2:
  946.                 fGetWord(inf, p);
  947.                 break;
  948.  
  949.             case DPL_UNS3:
  950.                 fGet3Byte(inf, p);
  951.                 break;
  952.  
  953.             case DPL_SGN4:
  954.                 fGetLong(inf, p);
  955.                 break;
  956.  
  957.             default:
  958.                 panic("HandleDVIFile l=%d", l);
  959.             }
  960.  
  961.             /*
  962.              * Now that we have the parameter, perform the
  963.              * command.
  964.              */
  965.             switch (DVI_DT(c)) {
  966.  
  967.             case DT_SET:
  968.             case DT_PUT:
  969.                 if (!UseThisPage)
  970.                     continue;
  971.                 if (!CurrentFontOK) {
  972.                     ReallyUseFont();
  973.                     CurrentFontOK++;
  974.                 }
  975.                 putbyte(outf, c);
  976.                 switch (l) {
  977.  
  978.                 case DPL_UNS1:
  979.                     putbyte(outf, p);
  980.                     CurrentPosition += 2;
  981.                     continue;
  982.  
  983.                 case DPL_UNS2:
  984.                     PutWord(outf, p);
  985.                     CurrentPosition += 3;
  986.                     continue;
  987.  
  988.                 case DPL_UNS3:
  989.                     Put3Byte(outf, p);
  990.                     CurrentPosition += 4;
  991.                     continue;
  992.  
  993.                 case DPL_SGN4:
  994.                     PutLong(outf, p);
  995.                     CurrentPosition += 5;
  996.                     continue;
  997.                 }
  998.  
  999.             case DT_FNT:
  1000.                 CurrentFontIndex = p;
  1001.                 CurrentFontOK = 0;
  1002.                 continue;
  1003.  
  1004.             case DT_XXX:
  1005.                 HandleSpecial(c, l, p);
  1006.                 continue;
  1007.  
  1008.             case DT_FNTDEF:
  1009.                 HandleFontDef(p);
  1010.                 continue;
  1011.  
  1012.             default:
  1013.                 panic("HandleDVIFile DVI_DT(%d)=%d",
  1014.                       c, DVI_DT(c));
  1015.             }
  1016.             continue;
  1017.         }
  1018.  
  1019.         switch (c) {    /* handle the few remaining cases */
  1020.  
  1021.         case DVI_BOP:
  1022.             if (doingpage)
  1023.                 GripeUnexpectedOp("BOP (during page)");
  1024.             BeginPage();
  1025.             doingpage = 1;
  1026.             CurrentFontOK = 0;
  1027.             break;
  1028.  
  1029.         case DVI_EOP:
  1030.             if (!doingpage)
  1031.                 GripeUnexpectedOp("EOP (outside page)");
  1032.             EndPage();
  1033.             doingpage = 0;
  1034.             break;
  1035.  
  1036.         case DVI_PRE:
  1037.             GripeUnexpectedOp("PRE");
  1038.             /* NOTREACHED */
  1039.  
  1040.         case DVI_POST:
  1041.             if (doingpage)
  1042.                 GripeUnexpectedOp("POST (inside page)");
  1043.             return;
  1044.  
  1045.         case DVI_POSTPOST:
  1046.             GripeUnexpectedOp("POSTPOST");
  1047.             /* NOTREACHED */
  1048.  
  1049.         default:
  1050.             GripeUndefinedOp(c);
  1051.             /* NOTREACHED */
  1052.         }
  1053.     }
  1054. }
  1055.